package lv.rtu.ditf.dc.fs;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;

import lazyj.Util;
import lv.rtu.ditf.dc.document.DocumentVectorUtils;
import lv.rtu.ditf.dc.stream.StringStreamReader;

/**
 * 
 * @author Pāvels Koliškins, Edgars Matisāns
 *
 */
public class Document {
	private final File documentFile;
	private final File indexFile;
	private HashMap<String, Integer> indexContent;

	
	private Document(File documentFile, File indexFile) {
		this.documentFile = documentFile;
		this.indexFile = indexFile;
	}
	
	
	public static Document get(File documentFile, File indexesDirectory) {
		if (documentFile == null || !documentFile.exists())
			throw new IllegalArgumentException("Document must exist");
		
		// ignore directories
		if (!documentFile.isFile())
			return null;
		
		// create virtual index file
		File indexFile = new File(indexesDirectory, documentFile.getName());
		
		return new Document(documentFile, indexFile);
	}

	
	public String getName() {
		return documentFile.getName();
	}
	
	
	public String getContent() {
		FileInputStream inStream = null;
		try {
			inStream = new FileInputStream(documentFile);
			return StringStreamReader.read(inStream, null);
		}
		catch (IOException e) {
			//TODO log
			e.printStackTrace();
		}
		finally {
			try {
				if (inStream != null)
					inStream.close();
			}
			catch (IOException e) {
				//TODO log
				e.printStackTrace();	
			}
		}
		
		return null;
	}
	
	



    public String getPlainTextContent() {
		String content = getContent();
		if (content == null)
			return null;
		
		return Util.htmlToText(content);
	}
	
	
	private HashMap<String, Integer> getTermFrequencies() {
		HashMap<String, Integer> termFrequencies;
		
		String plainText = getPlainTextContent();
		if (plainText != null)
			termFrequencies = DocumentVectorUtils.getDocumentVector(plainText);
		else
			termFrequencies = new HashMap<String, Integer>();
		
		return termFrequencies;
	}
	
	
	/**
	 * Gets term frequencies from "index" file.
	 * @return
	 */
	public HashMap<String, Integer> getPrecalculatedTermFrequencies() {		
		HashMap<String, Integer> termFrequencies = getIndex();
		if (termFrequencies != null)
			return termFrequencies;
			
		if (buildIndex()) {
			termFrequencies = getIndex();
			if (termFrequencies != null)
				return termFrequencies;
		}
		
		return getTermFrequencies(); 
	}
	
	
	public HashMap<String, Double> getTermWeights(int totalDocumentCount, HashMap<String, Integer> totalDocumentCountWithTerm) {
		HashMap<String, Double> termWeights = new HashMap<String, Double>();
		
		HashMap<String, Integer> frequencies = getPrecalculatedTermFrequencies();
		if (frequencies == null) {
			// TODO log
			System.out.println(String.format("No term frequencies found for document %s", documentFile.getName()));
			
			return termWeights;
		}
		
		long totalFreq = 0;
		for (Integer termFreqInThisDoc : frequencies.values()) {
			totalFreq += Math.pow(termFreqInThisDoc, 2);
		}
		double sqrtTotalFreq = Math.sqrt(totalFreq);
		
		for (String key : frequencies.keySet()) {
			int termFrequencyInThisDocument = frequencies.get(key);
			int documentCountContainingTerm = totalDocumentCountWithTerm.get(key);
			double logArg = (double) totalDocumentCount / documentCountContainingTerm;
			
			double termWeight = termFrequencyInThisDocument / sqrtTotalFreq * Math.log(logArg);
			termWeights.put(key, termWeight);
		}
		
		return termWeights;
	}

	
	public boolean buildIndex() {
		try {
			if (!indexFile.exists())
				indexFile.createNewFile();
			
			indexContent = getTermFrequencies();
			SerializationUtil.serializeHashMap(indexContent, indexFile);
			return true;
		}
		catch (IOException ex) {
			ex.printStackTrace();
		}
		
		return false;
	}
	
	
	private HashMap<String, Integer> getIndex() {
		if (indexContent == null) {
			boolean indexJustBuilt = false;
			
			if (indexFile.exists() || (!indexFile.exists() && (indexJustBuilt = buildIndex()))) {
				try {
					if (!indexJustBuilt)
						indexContent = SerializationUtil.deserializeHashMap(indexFile); 
				}
				catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
	
		return indexContent;
	}
}
